home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
World of Video
/
World of Video.iso
/
gfxprograms
/
3dprograms
/
rayshade-4.0
/
fixes
/
fix017
/
zbuf.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-02-13
|
11KB
|
379 lines
/*
* zbuf.c
*
* Add Z buffer support to Rayshade 4.0, by Mark W. Maimone (mwm@cs.cmu.edu)
*
* Rayshade is a rendering package by Craig Kolb, et al
* Copyright (C) 1989, 1991, Craig E. Kolb
* All rights reserved.
*
* This software may be freely copied, modified, and redistributed
* provided that this copyright notice is preserved on all copies.
*
* You may not distribute this software, in whole or in part, as part of
* any commercial product without the express consent of the authors.
*
* There is no warranty or other guarantee of fitness of this software
* for any purpose. It is provided solely "as is".
*
* zbuf.c,v 4.1 1994/08/09 07:44:49 explorer Exp
*
* zbuf.c,v
* Revision 4.1 1994/08/09 07:44:49 explorer
* Bump version to 4.1
*
* Revision 1.1.1.1 1994/08/08 04:51:55 explorer
* Initial import. This is a prerelease of 4.0.6enh3, or 4.1 possibly.
*
*/
#include "rayshade.h"
#include "options.h"
#include "zbuf.h"
#include "viewing.h"
typedef struct {
char *s;
int i;
} PairT;
RSZbuf zbuffer;
/* Must set the proper window size before calling ZbufSetup() */
void
ZbufSetup()
{
int horiz = Screen.xsize;
int vert = Screen.ysize;
int i, j;
if (Options.zbufname == (char *)NULL)
return;
if ((zbuffer.fzbuf = fopen (Options.zbufname, "w")) == NULL)
RLerror(RL_PANIC, "Cannot open Z buffer file \"%s\".\n",
Options.zbufname);
zbuffer.array = (Float **) Malloc (vert * sizeof (Float *));
/* Initialize all depths to Infinity */
for (i = 0; i < vert; i++) {
zbuffer.array[i] = (Float *) Malloc (horiz * sizeof (Float));
for (j = 0; j < horiz; j++)
zbuffer.array[i][j] = ZBUF_INF;
} /* for */
} /* ZbufSetup */
/* ZbufAdd -- Some object in pixel (x,y) is distance dist from the
eye. Add it to the Z buffer if it's nearer than all other objects seen
so far. This simple-minded storage scheme relies on the anti-aliasing
to sample the pixel at appropriate places. It also assumes you want
the distance of the *nearest* object touching the pixel as the final
distance measure. */
void ZbufAdd (x, y, dist)
Float x, y, dist;
{
int j = ((int) (x + 0.5)) - Screen.minx;
int i = ((int) (y + 0.5)) - Screen.miny;
if (zbuffer.array && i >= 0 && j >= 0 && i < Screen.ysize &&
j < Screen.xsize)
{
Float before = zbuffer.array[i][j];
if (before == ZBUF_INF || dist < before)
zbuffer.array[i][j] = dist;
}
} /* ZbufAdd */
/* ZbufPrint -- Write the Z buffer data to a file. Output format is
determined by the filename, or by DEFAULT_ZBUF_TYPE. Three formats
are available:
HF -- Output is written in Heightfield format
TXT -- After some opening comments, distances are written in
ascii. Each line in the output file contains distances for
the corresponding image line, separated by a single space.
TXT3 -- After some opening comments, distances are
output as a triple: pixel coordinate and distance (e.g.:
0 3 3.14146
means at position (0,3) the depth is 3.13146. This is very
space-inefficient, but is quite portable, and can be directly read by
GNUplot for easy viewing.
% rayshade -R 50 50 -z zbuf.dat Examples/balls.ray > balls.rle
% gnuplot
gnuplot> set term x11 [or whatever you're on]
gnuplot> set sample 2500 [for a 50x50 image]
gnuplot> set parametric [needed to plot 3D data]
gnuplot> splot 'zbuf.dat' with lines
[gives a nice height map grid]
gnuplot> help set view [info on changing viewpoint]
gnuplot> set view 45, 45 [a sample viewpoint]
gnuplot> quit
Warning! Distances are expected to always be positive, so background
pixels are represented by a distance of ZBUF_INF (i.e., -1000). To get
nice looking GNUplot output you should replace all -1's with the maximum
distance. On UNIX:
% rayshade -R 50 50 -z zbuf.dat Examples/planet.ray > balls.rle
% awk 'BEGIN {max = -1} NF == 3 { if ($3 > max) max = $3} END \
{print max}' < zbuf.dat [this gives you the max]
3.69359
% sed s/-1000/3.69359/g < zbuf.dat | awk 'NF == 3 { print $1" "$2" -"$3 \
; next} {print}' > zbuf.plot [replace -1 with max, make all
distances negative so the
plot appears rightside up]
% gnuplot
.
.
gnuplot> set zrange [-3.7:0]
gnuplot> splot 'zbuf.plot'
*/
static PairT exts[] = {
"hf", ZBUF_HF,
"rle", ZBUF_RLE,
"txt", ZBUF_TXT,
"txt3", ZBUF_TXT3, /* silly suffix, for backward compatability */
"etxt", ZBUF_TXT3,
}; /* exts */
void ZbufPrint ()
{
int type = ZsetOutputType (Options.zbufname);
int len = Screen.xsize;
int y;
FILE *fp = zbuffer.fzbuf;
char *filename = Options.zbufname;
if (PrepareForOutput (type, fp, filename) == 0)
return;
#ifdef URT
for (y = Screen.ysize-1; y >= 0; y--)
#else
for (y = 0; y < Screen.ysize; y++)
#endif
WriteRow (type, y + Screen.miny, fp, filename, zbuffer.array[y], len);
NoMoreThisImage (type, fp, filename);
} /* ZbufPrint */
int PrepareForOutput (type, fp, filename)
int type;
FILE *fp;
char *filename;
{
HEIGHTFIELD_SIZE i;
if (fp == NULL) return 0;
switch (type) {
case ZBUF_HF:
i = Screen.xsize;
if (i < Screen.ysize) i = Screen.ysize;
fwrite (&i, sizeof (HEIGHTFIELD_SIZE), 1, fp);
zbuffer.pad = i - Screen.xsize;
break;
case ZBUF_RLE:
fprintf (stderr, "Sorry, RLE output not available\n");
return 0;
case ZBUF_TXT:
case ZBUF_TXT3:
fprintf (fp, "# Rayshade Z-buffer output file for command:\n");
fprintf (fp, "# ");
ZwriteArgv (fp, zbuffer.argv);
if (zbuffer.rayfile)
fprintf (fp, "\n# Input RAY file: \"%s\"\n", zbuffer.rayfile);
if (zbuffer.outfile)
fprintf (fp, "# Output file: \"%s\"\n", zbuffer.outfile);
fprintf (fp, "# Resolution for this rendering is %dx%d\n",
Screen.xres, Screen.yres);
fprintf (fp, "# window from (%d,%d) to (%d,%d)\n",
Screen.minx, Screen.miny, Screen.maxx, Screen.maxy);
break;
default:
fprintf (stderr, "Error! Unknown Z buffer type '%d'\n", type);
return 0;
} /* switch */
return 1;
} /* PrepareForOutput */
WriteRow (type, y, fp, filename, row, len)
int type, y;
FILE *fp;
char *filename;
Float *row;
int len;
{
int i;
char *sep = "";
static float *padding = NULL;
static int pad_len = 0, vec_len = 0;
static float *vec = NULL;
switch (type) {
case ZBUF_HF:
if (vec_len < len) {
if (vec) free (vec);
vec_len = ((len+9) / 10) * 10;
vec = (float *) malloc (sizeof (float) * vec_len);
}
for (i = 0; i < len; i++)
vec[i] = (float) row[i];
fwrite (vec, sizeof (float), len, fp);
if (zbuffer.pad) {
if (pad_len < zbuffer.pad) {
if (padding) free (padding);
pad_len = ((zbuffer.pad+9) / 10) * 10;
padding = (float *) malloc (sizeof (float) * pad_len);
for (i = 0; i < pad_len; i++) padding[i] = ZBUF_INF;
} /* if */
fwrite (padding, sizeof (float), zbuffer.pad, fp);
}
break;
case ZBUF_TXT:
for (i = 0; i < len; i++) {
fprintf (fp, "%s%g", sep, row[i]);
sep = " ";
} /* for */
fprintf (fp, "\n");
break;
case ZBUF_TXT3:
for (i = 0; i < len; i++)
fprintf (fp, "%d %d %g\n", i + Screen.minx, y, row[i]);
fprintf (fp, "\n");
break;
default:
fprintf (stderr, "*Invalid type %d in WriteRow\n", type);
break;
} /* switch */
} /* WriteRow */
NoMoreThisImage (type, fp, filename)
int type;
FILE *fp;
char *filename;
{
if (type == ZBUF_HF)
if (Screen.xsize > Screen.ysize) {
int len = Screen.xsize - Screen.ysize;
int i;
float *padding = (float *) malloc (sizeof (float) * Screen.xsize);
for (i = 0; i < Screen.xsize; i++)
padding[i] = ZBUF_INF;
while (len-- > 0)
fwrite (padding, sizeof (float), Screen.xsize, fp);
free (padding);
} /* if */
fclose (fp);
zbuffer.fzbuf = NULL;
} /* NoMoreThisImage */
ZwriteArgv (fp, argv)
FILE *fp;
char **argv;
{
char *sep = "";
if (fp == NULL || argv == NULL) return;
while (*argv) {
fprintf (fp, "%s%s", sep, *argv);
sep = " ";
argv++;
}
} /* ZwriteArgv */
int ZsetOutputType (filename)
char *filename;
{
int i, len;
int type = DEFAULT_ZBUF_TYPE;
if (filename != NULL) {
len = strlen (filename);
for (i = 0; i < sizeof (exts) / sizeof (PairT); i++)
if (len >= strlen (exts[i].s) && strcmp (exts[i].s,
filename + len - strlen (exts[i].s)) == 0) {
type = exts[i].i;
break;
} /* if */
} /* if */
/* No RLE output yet */
if (type == ZBUF_RLE) {
fprintf (stderr,
" (Z buffer not in available in RLE format yet, sorry)\n");
type = DEFAULT_ZBUF_TYPE;
} /* if */
if (type) {
fprintf (stderr, "Z buffer will be written in ");
switch (type) {
case ZBUF_HF: fprintf (stderr, "HEIGHTFIELD"); break;
case ZBUF_TXT: fprintf (stderr, "TEXT"); break;
case ZBUF_TXT3: fprintf (stderr, "EXPANDED TEXT"); break;
case ZBUF_RLE: fprintf (stderr, "UTAH RASTER TOOLKIT"); break;
default: fprintf (stderr, "UNKNOWN!!");
type = 0; break;
} /* switch */
fprintf (stderr, " format to \"%s\"\n", Options.zbufname);
} /* if */
return type;
} /* ZsetOutputType */
#ifdef SDfl
void ZbufPrint ()
{
FILE *fp = zbuffer.fzbuf;
int minx = Screen.minx, maxx = Screen.maxx;
int miny = Screen.miny, maxy = Screen.maxy;
int horiz = Screen.xsize;
int vert = Screen.ysize;
int x, y;
if (fp == NULL)
return;
fprintf (fp, "# Depth Map for Rayshade output file\n");
if (zbuffer.rayfile)
fprintf (fp, "# Input RAY file: \"%s\"\n", zbuffer.rayfile);
if (zbuffer.outfile)
fprintf (fp, "# Output file: \"%s\"\n", zbuffer.outfile);
fprintf (fp, "# Resolution for this rendering is %dx%d\n",
Screen.xres, Screen.yres);
fprintf (fp, "# window from (%d,%d) to (%d,%d)\n",
minx, miny, maxx, maxy);
fprintf (fp, "# Screen X unit vector: (%g,%g,%g)\n",
Screen.scrnx.x, Screen.scrnx.y, Screen.scrnx.z);
fprintf (fp, "# Screen Y unit vector: (%g,%g,%g)\n",
Screen.scrny.x, Screen.scrny.y, Screen.scrny.z);
/* Would be nice to save command-line options too */
for (x = 0; x < horiz; x++)
{
for (y = 0; y < vert; y++)
fprintf (fp, "%d %d %g\n", x, y, zbuffer.array[x][y]);
fprintf (fp, "\n");
} /* for */
fclose (fp);
zbuffer.fzbuf = NULL;
} /* ZbufPrint */
#endif